// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 

using System;
using System.Collections.Generic;

using Anculus.Core;

using Galaxium.Protocol.Xmpp.Library.Xml;
using Galaxium.Protocol.Xmpp.Library.Core;
using Galaxium.Protocol.Xmpp.Library.Extensions;
using Galaxium.Protocol.Xmpp.Library.Extensions.Disco;

namespace Galaxium.Protocol.Xmpp.Library
{
	public class ResourceInfo: IComparable<ResourceInfo>
	{
		public event EventHandler InfoUpdated;
		
		private Info _info;
		private Element _current_caps;
		private bool _requested;
		
		private SoftwareVersion _version;
		
		public Presence Presence { get; private set; }
		
		public Contact Contact { get; private set; }
		public string Identifier { get; private set; }
		
		public JabberID FullJid { get; private set; }
		
		public IEnumerable<Identity> Identities {
			get { return (_info == null ? null : _info.Identities) ?? new Identity [0]; }
		}
		
		public IEnumerable<string> Features {
			get { return (_info == null ? null : _info.Features) ?? new String [0]; }
		}
		
		public ResourceInfo (Contact contact, string resource)
		{
			Contact = contact;
			Identifier = resource;
			FullJid = new JabberID (Contact.Jid.Node, Contact.Jid.Domain, Identifier);
		}
		
		public string GetClientName ()
		{
			if (_version != null)
				return _version.Name + " " + _version.Version;
			
			if (Supports (Namespaces.Version)) {
				try {
					_version = SoftwareVersion.Get (Contact.Client, FullJid);
					return _version.Name + " " + _version.Version;
				}
				catch {}
			}
			
			foreach (var identity in Identities) {
				if (identity.Category == "client")
					return identity.Name;
			}
			
			return null;
		}
		
		public string GetOperatingSystem ()
		{
			if (_version != null)
				return _version.OperatingSystem;
			
			if (Supports (Namespaces.Version)) {
				try {
					_version = SoftwareVersion.Get (Contact.Client, FullJid);
					return _version.OperatingSystem;
				}
				catch {}
			}
			
			return null;
		}
		
		public bool Supports (string feature)
		{
			return _info != null && _info.Supports (feature);
		}
		
		public void UpdatePresence (Presence pres)
		{
			Presence = pres;
			HandleCaps ();
		}
		
		private void HandleCaps ()
		{
			var caps = Presence.FirstChild ("c", Namespaces.Capabilities);
			if (_current_caps != null && _current_caps ["ver"] == caps ["ver"]) return;
			_current_caps = caps;
			
			if (_current_caps == null) {
				if (Presence.Type != PresType.Error)
					RequestInfo ();
			}
			else CapsHelper.Retrieve (Contact.Client, FullJid, _current_caps, UpdateInfo);
		}
		
		private void RequestInfo ()
		{
			if (_requested) return; // only request once
			_requested = true;
			
			var request = new InfoRequest (Contact.Client, FullJid, null);
			request.ReceivedEvent += (s, e) => UpdateInfo ((s as InfoRequest).Result);
			request.Request ();
		}
		
		private void UpdateInfo (Info info)
		{
			_info = info;
			if (InfoUpdated != null)
				InfoUpdated (this, EventArgs.Empty);
		}
		
		public int CompareTo (ResourceInfo other)
		{
			return Presence.CompareTo (other.Presence);
		}
	}
}
